package com.vf.system.common;

import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import com.vf.common.utils.ip.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.*;
import java.net.*;
import java.util.regex.Pattern;

/**
 * IP地址定位工具类
 * 实现了IP地址到地理位置的高效转换
 */
@Slf4j
public class IpSearchUtil {

    // 私有IP地址匹配模式
    private static final Pattern PRIVATE_IP_PATTERN = Pattern.compile(
            "(^(10\\.)|^(172\\.1[6-9]\\.)|^(172\\.2[0-9]\\.)|^(172\\.3[0-1]\\.)|^(192\\.168\\.)|^(127\\.)|^(169\\.254\\.)).*");

    // IPv4地址验证模式（已正确转义）
    private static final String IPV4_PATTERN =
            "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";

    // IP数据库搜索器实例
    private static Searcher searcher;

    static {
        try {
            // 初始化IP数据库搜索器
            InputStream inputStream = new PathMatchingResourcePatternResolver()
                    .getResource("classpath:/xdb/ip2region.xdb").getInputStream();
            log.info("加载IP数据库文件: {}", inputStream);

            FastByteArrayOutputStream stream = IoUtil.read(inputStream);
            searcher = Searcher.newWithBuffer(stream.toByteArray());
        } catch (IOException e) {
            log.error("加载IP数据库文件失败", e);
        }
    }

    /**
     * 通过IP地址获取地区信息
     *
     * @param ip IP地址（可为null）
     * @return 地区信息字符串
     */
    public static String getAddressFromIp(String ip) {
        String ipAddress = null;

        try {
            // 如果传入了有效IP且不是私有地址，直接使用它
            if (ip != null && !ip.isEmpty() && !isPrivateIp(ip) && isValidIp(ip)) {
                log.info("使用提供的公网IP: {}", ip);
                ipAddress = ip;
            } else {
                // 否则获取本机公网IP
                ipAddress = getOutboundIpAddress();
                log.info("使用本机公网IP: {}", ipAddress);
            }

            // 执行IP地址搜索
            String result = searcher.search(ipAddress);
            log.info("IP定位结果: {}", result);

            return result;
        } catch (Exception e) {
            log.error("IP定位搜索失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取客户端城市信息
     *
     * @param ip 客户端IP地址
     * @return 城市名称 城市解析IP地址
     */
    public static String getCityFromIp(String ip) {
        String address = getAddressFromIp(ip);

        if (address == null || address.isEmpty()) {
            return null;
        }

        String[] split = address.split("\\|");
        return split.length > 1 ? split[split.length - 2] : null;
    }

    /**
     * 获取本机公网IP地址
     *
     *
     * @return 公网IP地址
     * @throws IOException 如果网络操作失败
     * @throws RuntimeException 如果无法获取有效的公网IP地址
     */
    public static String getOutboundIpAddress() throws IOException {
        String localIp = IpUtils.getIpAddr();
        log.info("请求IP地址: {}", localIp);

        // 如果当前IP已经是公网IP，直接返回
        if (!isPrivateIp(localIp)) {
            log.info("远程IP地址: {}", localIp);
            return localIp;
        }

        // 多个IP服务提供者实现故障转移
        String[] ipServices = {
                "http://checkip.amazonaws.com",
                "http://ifconfig.me/ip",
                "http://whatismyip.akamai.com"
        };

        for (String serviceUrl : ipServices) {
            try {
                URL url = new URL(serviceUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();

                // 设置连接参数
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(5000);
                connection.setReadTimeout(5000);
                connection.setInstanceFollowRedirects(true);

                int responseCode = connection.getResponseCode();

                if (responseCode == HttpURLConnection.HTTP_OK) {
                    try (BufferedReader reader = new BufferedReader(
                            new InputStreamReader(connection.getInputStream()))) {

                        StringBuilder ipAddress = new StringBuilder();
                        String line;

                        while ((line = reader.readLine()) != null) {
                            ipAddress.append(line.trim());
                        }

                        String ip = ipAddress.toString();
                        if (isValidIp(ip)) {
                            log.info("成功从 {} 获取有效的公网IP: {}", serviceUrl, ip);
                            return ip;
                        } else {
                            log.warn("从 {} 获取的IP地址无效: {}", serviceUrl, ip);
                        }
                    }
                } else {
                    log.warn("从 {} 获取IP失败，HTTP响应码: {}", serviceUrl, responseCode);
                }
            } catch (Exception e) {
                log.warn("从 {} 获取IP失败: {}", serviceUrl, e.getMessage());
            }
        }

        throw new RuntimeException("无法获取有效的公网IP地址");
    }

    /**
     * 判断IP地址是否为内网IP
     *
     * @param ip IP地址
     * @return 是否为内网IP
     */
    public static boolean isPrivateIp(String ip) {
        if (ip == null || ip.isEmpty()) {
            log.warn("IP地址为空，视为无效私有IP");
            return true;
        }

        boolean isPrivate = PRIVATE_IP_PATTERN.matcher(ip).matches();
        log.debug("IP {} 是{}私有地址", ip, isPrivate ? "" : "非 ");
        return isPrivate;
    }

    /**
     * 验证IP地址格式是否有效 没有效果就换成正则
     *
     * @param ip IP地址字符串
     * @return 是否为有效的IPv4地址
     */
    private static boolean isValidIp(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }

        boolean isValid = ip.matches(IPV4_PATTERN);
        if (!isValid) {
            log.debug("IP地址 {} 不符合IPv4格式要求", ip);
        }
        return isValid;
    }
    
}
